home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / srcuc.zip / DOSCONIO.C < prev    next >
C/C++ Source or Header  |  1992-05-05  |  13KB  |  466 lines

  1. /* -*-C-*-
  2.  
  3. $Header: /scheme/dos386/microcode/RCS/dosconio.c,v 1.1 1992/05/05 06:55:13 jinx Exp $
  4.  
  5. Copyright (c) 1992 Massachusetts Institute of Technology
  6.  
  7. This material was developed by the Scheme project at the Massachusetts
  8. Institute of Technology, Department of Electrical Engineering and
  9. Computer Science.  Permission to copy this software, to redistribute
  10. it, and to use it for any purpose is granted, subject to the following
  11. restrictions and understandings.
  12.  
  13. 1. Any copy made of this software must include this copyright notice
  14. in full.
  15.  
  16. 2. Users of this software agree to make their best efforts (a) to
  17. return to the MIT Scheme project any improvements or extensions that
  18. they make, so that these may be included in future releases; and (b)
  19. to inform MIT of noteworthy uses of this software.
  20.  
  21. 3. All materials developed as a consequence of the use of this
  22. software shall duly acknowledge such use, in accordance with the usual
  23. standards of acknowledging credit in academic research.
  24.  
  25. 4. MIT has made no warrantee or representation that the operation of
  26. this software will be error-free, and MIT is under no obligation to
  27. provide any services, by way of maintenance, update, or otherwise.
  28.  
  29. 5. In conjunction with products arising from the use of this material,
  30. there shall be no use of the name of the Massachusetts Institute of
  31. Technology nor of any adaptation thereof in any advertising,
  32. promotional, or sales literature without prior written consent from
  33. MIT in each case. */
  34.  
  35. /* Console I/O supplement */
  36.  
  37. #include "scheme.h"
  38. #include "prims.h"
  39. #include "msdos.h"
  40. #include "dosio.h"
  41. #include "dosscan.h"
  42. #include "dossys.h"
  43. #include "intrpt.h"
  44.  
  45. /* This is really not set up to include Scheme level headers, so we
  46.    fake them here. */
  47. extern long
  48.   IntCode,        /* Interrupts requesting */
  49.   IntEnb;        /* Interrupts enabled */
  50.  
  51. #ifdef __STDC__
  52. #define fileno(fp)    ((fp)->_file)
  53. #endif
  54.  
  55.  
  56. #define CONIO_BUFFER_SIZE    (1024)
  57. #define TYPEAHEAD_BUFFER_SIZE    (1024)
  58.  
  59. #define System_Error_Reset()        \
  60.   (errno = 0)
  61.  
  62. #define System_Error_Return(err)    \
  63. {                    \
  64.   errno = err;                \
  65.   return -1;                \
  66. }
  67.  
  68. /* Characters are kept in the typeahead_buffer before read is called,
  69.    in the key_buffer before return is pressed, and in the line_buffer
  70.    before the line is read.
  71.  */
  72. typedef    struct conin_buffer_struct
  73. {
  74.   unsigned char buffer[CONIO_BUFFER_SIZE];
  75.   size_t length;
  76. } conio_buffer_t;
  77.  
  78. typedef struct typeahead_buffer_struct
  79. {
  80.   unsigned char buffer[TYPEAHEAD_BUFFER_SIZE];
  81.   size_t length;
  82. } typeahead_buffer_t;
  83.  
  84. static conio_buffer_t line_buffer, key_buffer;
  85. static typeahead_buffer_t typeahead_buffer;
  86.  
  87.  
  88. static int max_scancode_conversion_length = 0;
  89. static unsigned char * keyboard_scancode_table[] = DEFAULT_SCANCODE_CONVERSIONS;
  90.  
  91. /* This is a kludge to save 200 bytes or so of memory; sigh! */
  92. #ifndef ULONG_BIT
  93. #define ULONG_BIT        (sizeof(unsigned long)*CHAR_BIT)
  94. #endif
  95. #define MALLOCED_TABLE_SIZE    \
  96.   ((KEYBOARD_SCANCODE_TABLE_SIZE+(ULONG_BIT-1))/ULONG_BIT)
  97.  
  98. static unsigned long scancode_malloced_table[MALLOCED_TABLE_SIZE] = {0,};
  99.  
  100. #define Scancode_To_Malloced_Table_Word(s)    ((s)/ULONG_BIT)
  101. #define Scancode_To_Malloced_Table_Word_Bit(s)    ((s)%ULONG_BIT)
  102.  
  103. #define Scancode_Malloced_p(s)                        \
  104.   (scancode_malloced_table[Scancode_To_Malloced_Table_Word(s)] &    \
  105.    (1 << Scancode_To_Malloced_Table_Word_Bit(s)))
  106.  
  107. #define Scancode_Malloced(s)                        \
  108.   (scancode_malloced_table[Scancode_To_Malloced_Table_Word(s)] |=    \
  109.    (1 << Scancode_To_Malloced_Table_Word_Bit(s)))
  110.  
  111. #define Scancode_Malloced_Not(s)                    \
  112.   (scancode_malloced_table[Scancode_To_Malloced_Table_Word(s)] &=    \
  113.    (~(1 << Scancode_To_Malloced_Table_Word_Bit(s))))
  114.  
  115. /* End of Kludge */
  116.  
  117. #define Max(a, b) (((a) > (b)) ? (a) : (b))
  118.  
  119. #define Typeahead_Buffer_Remaining()    \
  120.   (TYPEAHEAD_BUFFER_SIZE - typeahead_buffer.length)
  121.  
  122. #define Typeahead_Buffer_Available_p()    \
  123.   (Typeahead_Buffer_Remaining() >= max_scancode_conversion_length)
  124.  
  125. static void
  126. DEFUN (map_keyboard_scancode, (scancode), unsigned char scancode)
  127. { extern int signal_keyboard_character_interrupt(unsigned char);
  128.  
  129.   if (scancode < KEYBOARD_SCANCODE_TABLE_SIZE)
  130.   {
  131.     int len;
  132.     unsigned char * conversion = keyboard_scancode_table[scancode];
  133.     if (conversion == NO_CONVERSION)
  134.       return;
  135.  
  136.     len = ((conversion == CTRL_AT) ? 1 : strlen (conversion));
  137.     
  138.     if (len <= (Typeahead_Buffer_Remaining ()))
  139.     { /* Copy conversion string into typeahead buffer, worrying about
  140.      interrupt characters along the way. */
  141.       while (--len >= 0)
  142.       {
  143.     if ((signal_keyboard_character_interrupt (*conversion)) == 0)
  144.       typeahead_buffer.buffer[typeahead_buffer.length++] = *conversion++;
  145.       }
  146.     }
  147.   }
  148.   return;
  149. }
  150.  
  151. static void
  152. DEFUN_VOID (recompute_max_scancode_conversion_length)
  153. {
  154.   int i, length;
  155.   max_scancode_conversion_length = 0;
  156.  
  157.   for (i = 0; i < KEYBOARD_SCANCODE_TABLE_SIZE; i++)
  158.   { 
  159.     unsigned char * conversion = keyboard_scancode_table[i];
  160.     if (conversion == NO_CONVERSION)
  161.       length = 0;
  162.     else if (conversion == CTRL_AT)
  163.       length = 1;
  164.     else
  165.       length = strlen (conversion);
  166.     max_scancode_conversion_length 
  167.       = Max (length, max_scancode_conversion_length);
  168.   }
  169.   return;
  170. }
  171.  
  172. static void
  173. DEFUN_VOID (initialize_scancode_table)
  174. {
  175.   recompute_max_scancode_conversion_length ();
  176. }
  177.  
  178. DEFINE_PRIMITIVE ("KEYBOARD-GET-CONVERSION", Prim_keyboard_get_conversion,
  179.           1, 1, 0)
  180. {
  181.   PRIMITIVE_HEADER (1);
  182.   {
  183.     long scancode = arg_integer(1);
  184.  
  185.     if ((scancode < 0) || (scancode >= KEYBOARD_SCANCODE_TABLE_SIZE))
  186.       error_bad_range_arg(1);
  187.     else
  188.     {
  189.       unsigned char * conversion = keyboard_scancode_table[scancode];
  190.       if (conversion == NO_CONVERSION)
  191.     PRIMITIVE_RETURN (SHARP_F);
  192.       else if (conversion == CTRL_AT)
  193.     PRIMITIVE_RETURN (memory_to_string (1, "\0"));
  194.       else
  195.     PRIMITIVE_RETURN (char_pointer_to_string (conversion));
  196.     }
  197.   }
  198. }
  199.  
  200. DEFINE_PRIMITIVE ("KEYBOARD-SET-CONVERSION!", Prim_keyboard_set_conversion,
  201.           2, 2, 0)
  202. {
  203.   PRIMITIVE_HEADER (2);
  204.   {
  205.     int scancode = arg_integer (1);
  206.     SCHEME_OBJECT scheme_conversion = ARG_REF (2);
  207.  
  208.     if ((scancode < 0) || (scancode >= KEYBOARD_SCANCODE_TABLE_SIZE))
  209.       error_bad_range_arg(1);
  210.     else
  211.     { 
  212.       int len;
  213.       if ((scheme_conversion != SHARP_F)
  214.       && (!STRING_P (scheme_conversion)))
  215.     error_wrong_type_arg (2);
  216.       if ((scheme_conversion == SHARP_F)
  217.       || ((len = (STRING_LENGTH (scheme_conversion)))
  218.           == 0))
  219.       {
  220.     if (Scancode_Malloced_p (scancode))
  221.       DOS_free (keyboard_scancode_table[scancode]);
  222.     keyboard_scancode_table[scancode] = NO_CONVERSION;
  223.     Scancode_Malloced_Not (scancode);
  224.       }
  225.       else if ((len == 1)
  226.            && ((STRING_REF (scheme_conversion, 0)) == '\0'))
  227.       {
  228.     if (Scancode_Malloced_p (scancode))
  229.       DOS_free (keyboard_scancode_table[scancode]);
  230.     keyboard_scancode_table[scancode] = CTRL_AT;
  231.     Scancode_Malloced_Not (scancode);
  232.       }
  233.       else
  234.       {
  235.     int i;
  236.     unsigned char * old_conversion
  237.       = keyboard_scancode_table[scancode];
  238.     unsigned char * conversion, * scheme;
  239.  
  240.     conversion = (DOS_malloc (len + 1));
  241.     if (conversion == 0)
  242.       error_system_call (ENOMEM, syscall_malloc);
  243.     if (Scancode_Malloced_p (scancode))
  244.       DOS_free (old_conversion);
  245.     keyboard_scancode_table[scancode] = conversion;
  246.     Scancode_Malloced (scancode);
  247.     for (i = 0, scheme = (STRING_LOC (scheme_conversion, 0));
  248.          i <= len;
  249.          i ++)
  250.       *conversion++ = *scheme++;
  251.     *conversion = '\0';
  252.       }
  253.       recompute_max_scancode_conversion_length ();
  254.       PRIMITIVE_RETURN (UNSPECIFIC);
  255.     }
  256.   }
  257. }
  258.  
  259. static void
  260. DEFUN_VOID (consume_typeahead)
  261. {
  262.   extern int signal_keyboard_character_interrupt(unsigned char);
  263.   unsigned char character;
  264.  
  265.   while ( (Typeahead_Buffer_Available_p()) &&
  266.       (dos_poll_keyboard_character(&character)) )
  267.   { 
  268.     if (character == '\0') /* Extended scancode */
  269.     { 
  270.       dos_poll_keyboard_character(&character);
  271.       map_keyboard_scancode(character);
  272.     }
  273.     else if (signal_keyboard_character_interrupt(character) == 0)
  274.       typeahead_buffer.buffer[typeahead_buffer.length++] = character;
  275.     else
  276.       break;
  277.   }
  278.   return;
  279. }
  280.  
  281. static int
  282. DEFUN_VOID (typeahead_available_p)
  283. {
  284.   consume_typeahead();
  285.   return !(typeahead_buffer.length == 0);
  286. }
  287.  
  288. static unsigned char
  289. DEFUN_VOID (get_typeahead_character)
  290. { unsigned char result;
  291.   
  292.   if (typeahead_buffer.length == 0)
  293.     return '\0';
  294.   else
  295.   { int i;
  296.     result = typeahead_buffer.buffer[0];
  297.     for (i = 1; i < typeahead_buffer.length; i++)
  298.       typeahead_buffer.buffer[i - 1] = typeahead_buffer.buffer[i];
  299.     typeahead_buffer.length--;
  300.     return result;
  301.   }
  302. }
  303.  
  304. DEFINE_PRIMITIVE ("CONSUME-TYPEAHEAD", Prim_consume_typeahead, 0, 0,
  305.   "Suck up DOS typeahead.")
  306. {
  307.  
  308.   PRIMITIVE_HEADER(0);
  309.   consume_typeahead();
  310.   PRIMITIVE_RETURN (UNSPECIFIC);
  311. }
  312.  
  313.  
  314. static void
  315. DEFUN (key_buffer_insert_self, (c), unsigned char c)
  316. {
  317.   static unsigned char crlf[] = {CARRIAGE_RETURN, LINEFEED};
  318.  
  319.   if (key_buffer.length != CONIO_BUFFER_SIZE)
  320.   {
  321.     key_buffer.buffer[key_buffer.length++] = c;
  322.     ( (c == LINEFEED)
  323.       ? dos_console_write(crlf, sizeof(crlf))
  324.       : dos_console_write(&c, 1) );
  325.   }
  326.   return;
  327. }  
  328.  
  329. static void
  330. DEFUN_VOID (key_buffer_erase_character)
  331. {
  332.   static char erase[] = {BACKSPACE, SPACE, BACKSPACE};
  333.  
  334.   if (key_buffer.length != 0)
  335.   {
  336.     key_buffer.length -= 1;
  337.     dos_console_write(erase, sizeof(erase));
  338.   }
  339.   return;
  340. }
  341.  
  342. static void
  343. DEFUN_VOID(key_buffer_to_line_buffer)
  344. { register size_t i = 0;
  345.   register size_t j = 0;
  346.  
  347.   while ((i < key_buffer.length)&&(line_buffer.length != CONIO_BUFFER_SIZE))
  348.     line_buffer.buffer[line_buffer.length++] = key_buffer.buffer[i++];
  349.   while (i < key_buffer.length)
  350.     key_buffer.buffer[j++] = key_buffer.buffer[i++];
  351.   key_buffer.length = j;
  352.  
  353.   return;
  354. }
  355.  
  356.  
  357.  
  358. void
  359. DEFUN_VOID (flush_conio_buffers)
  360. {
  361.   line_buffer.length = 0;
  362.   key_buffer.length = 0;
  363.   typeahead_buffer.length = 0;
  364.   return;
  365. }
  366.  
  367. void
  368. DEFUN_VOID (DOS_initialize_conio)
  369. { void initialize_keyboard_interrupt_table(void);
  370.  
  371.   flush_conio_buffers();
  372.   initialize_keyboard_interrupt_table();
  373.   initialize_scancode_table();
  374.  
  375.   return;
  376. }
  377.  
  378.  
  379. static int
  380. DEFUN(empty_line_buffer, (buffer, nbytes), char * buffer AND size_t nbytes)
  381. { register size_t i, j;
  382.   
  383.   for (i = 0; ((i < line_buffer.length)&&(i < nbytes)); i++)
  384.     *buffer++ = line_buffer.buffer[i];
  385.   nbytes = i;
  386.   for (j = 0; i < line_buffer.length; i++, j++)
  387.     line_buffer.buffer[j] = line_buffer.buffer[i];
  388.   line_buffer.length -= nbytes;
  389.   return nbytes;
  390. }
  391.  
  392.  
  393. static void
  394. DEFUN (buffered_key_command, (c), unsigned char c)
  395. {
  396.   switch(c)
  397.   { 
  398.     case CARRIAGE_RETURN:
  399.     case LINEFEED:
  400.       key_buffer_insert_self(LINEFEED);
  401.       key_buffer_to_line_buffer();
  402.       break;
  403.     case DELETE:
  404.     case BACKSPACE: /* Backspace */
  405.       if (key_buffer.length != 0)
  406.     key_buffer_erase_character();
  407.       break;
  408.     default:
  409.       key_buffer_insert_self(c);
  410.       break;
  411.   }
  412.   return;
  413. }
  414.  
  415. static void
  416. DEFUN (non_buffered_key_command, (c), unsigned char c)
  417. {
  418.   if (line_buffer.length == CONIO_BUFFER_SIZE) return;
  419.  
  420.   if ((!DOS_keyboard_intercepted_p)
  421.       && (c == BACKSPACE))
  422.     c = DELETE;
  423.  
  424.   line_buffer.buffer[line_buffer.length++] = c;
  425.   return;
  426. }
  427.  
  428. long
  429. DEFUN(console_read, (buffer, nbytes, buffered_p, blocking_p),
  430.       char * buffer AND unsigned nbytes AND int buffered_p AND int blocking_p)
  431.   System_Error_Reset();
  432.   do
  433.   { /* Get all pending characters into the buffer */
  434.     while (typeahead_available_p())
  435.     { 
  436.       if (buffered_p)
  437.     buffered_key_command(get_typeahead_character());
  438.       else /* Non buffered channel, in CScheme, also no echo. */
  439.           non_buffered_key_command(get_typeahead_character());
  440.     } /* End WHILE */
  441.     /* Test for pending interrupts here: */
  442.     if (pending_interrupts_p())
  443.     { if (INTERRUPT_QUEUED_P(INT_Character))
  444.     flush_conio_buffers();
  445.       System_Error_Return(EINTR);
  446.     }
  447.     /* Return if we buffered up a line, or channel is not buffered */
  448.     if (line_buffer.length != 0)
  449.       return empty_line_buffer(buffer, nbytes);
  450.   } while (blocking_p);    /* Keep reading for blocking channel. */
  451.   /* This means there is nothing available, don't block */
  452.   System_Error_Return(ERRNO_NONBLOCK);
  453. }
  454.     
  455.  
  456. extern int EXFUN
  457.  (text_write, (int fd AND CONST unsigned char * buffer AND size_t nbytes));
  458.  
  459. void
  460. DEFUN (console_write_string, (string), void * string)
  461. {
  462.   text_write(fileno(stdout), string, strlen((char *) string));
  463.   return;
  464. }
  465.